<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
 * FormativeLab
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		FormativeLab
 * @author		FormativeLab Dev Team
 * @copyright	Copyright (c) 2011 - 2013, FormativeLab, Inc.
 * @license		http://www.formativesoft.com/license/
 * @link		http://www.formativesoft.com/
 * @since		Version 2.0
 * @filesource ./application/libraries/Authentication.php
 */

// ------------------------------------------------------------------------

/**
 * FormativeLab Authentication Library
 *
 * @package		FormativeLab
 * @subpackage	libraries
 * @category	libraries
 * @author		Formative Soft Ltd
 * @link		http://www.formativesoft.com/
 */

// ------------------------------------------------------------------------

/**
 * Authentication class use for Authenticate and Authorization in CodeIgniter
 * MVC . This class is a CodeIgniter customized library used for customized 
 * security.
 **/
class Authentication{

	/**
	 * CodeIgniter Instance property. loaded during the initialization 
	 * of class. This intance is required to load others properties.
	 **/
	private $controller;
	
	/**
	 * CodeIgniter helpers and library. these are loaded during the 
	 * initialization of class.
	 **/
	private $input;
	private $output;
	private $session;
	private $formValid;
	
	/**
	 * CodeIgniter Security Configuration property are restricted private
	 * scope. this Configuration are automatically loaded during the
	 * initialization of class.
	 **/
	private $encrypt;
	private $salt;
	private $loginPage;
	private $loginSuccessMessage;
	private $loginSuccessPage;
	private $loginFailurePage;
	private $loginFailureMessage;
	private $logoutPage;
	private $logoutSuccessMessage;
	private $sessionTimeOutMessage;
	private $authorizationFailureMessage;
	
	/**
	 * CodeIgniter Security properties for Authentication these properties
	 * are use for swaping data during the performing Authentication process
	 **/
	private $username;
	private $passwrod;
	private $message;
	
	/**
	 * CodeIgniter Security Configuration property mapping use for load
	 * configuration automatically during the initialization of class.
	 **/
	static $securityConfigMapping = array(
		'encrypt'				=> 'encrypt',
		'salt'					=> 'salt',
		'loginPage'				=> 'login_page',
		'loginSuccessMessage'	=> 'login_success_msg',
		'loginSuccessPage'		=> 'login_success_page',
		'loginFailurePage'		=> 'login_failure_page',
		'loginFailureMessage'			=> 'login_failure_msg',
		'logoutPage'					=> 'logout_page',
		'logoutSuccessMessage'			=> 'logout_success_msg',
		'sessionTimeOutMessage'			=> 'session_time_out_msg',
		'authorizationFailureMessage'	=> 'authorization_failure_msg'
	);
	
	/**
	 * CodeIgniter runtime required helpers and library to load automatically
	 * during the initialization of class.
	 **/
	static $helper 		= array('security', 'url', 'method', 'resource');
	static $library		= array('form_validation','session');
	
	/**
	 * Constraints declaration for session keys and security configuation key
	 **/
	const ROLES			= 'roles';
	const USER_DATA		= 'user_data';
	const SECURITY_CFG  = 'security';

	/**
	 * __construct() used to initialized intance objects, properties and 
	 * configuration. It's also load required library and helpers
	 *
	 * @access	public
	 * @return  void 
	 **/
    public function __construct(){
        $this->controller = &get_instance();
		$this->loadSecurityConfig();
		
		$this->controller->load->helper(self::$helper);
        $this->controller->load->library(self::$library);
		
		$this->input  		= &$this->controller->input;
		$this->output 		= &$this->controller->output;
		$this->session 		= &$this->controller->session;
		$this->formValid	= &$this->controller->form_validation;
    }
	
	/**
	 * loadSecurityConfig() used to load  security configuration from
	 * security config file.
	 *
	 * @access	private
	 * @return  void 
	 **/
	private function loadSecurityConfig(){
		$this->controller->config->load(self::SECURITY_CFG);
		foreach(self::$securityConfigMapping as $property => $key){
			$this->{$property} = $this->controller->config->item($key);
		}
	}
	
	/**
	 * loadUserNameAndPassword() used to load  username and password
	 * from Authentication form submitted data.
	 *
	 * @access	private
	 * @return  void 
	 **/
	private function loadUserNameAndPassword(){
		$this->username = $this->input->post('username');
        $this->password = $this->input->post('password');
	}
	
	/**
	 * setUserData() used to store user data into session variable for
	 * futher Authentication and authorization process.
	 *
	 * @access	private
	 * @param	data
	 * @return  void 
	 **/
	private function setUserData(Array $data){
		$userData = array(self::USER_DATA => $data);
		$this->session->set_userdata($userData);
	}
	
	/**
	 * getUserData() used to retrieve stored user data from session variable
	 * for Authentication and authorization process.
	 *
	 * @access	private
	 * @return  array 
	 **/
	private function getUserData(){
		return $this->session->userdata(self::USER_DATA);
	}
	
	/**
	 * getAllUserData() used to retrieve stored all data from session variable
	 * for Authentication, authorization or others process.
	 *
	 * @access	private
	 * @return  array 
	 **/
	private function getAllUserData(){
		return $this->session->all_userdata();
	}
	
	/**
	 * getUserRoles() used to retrieve stored user roles from session variable
	 * for authorization process.
	 *
	 * @access	private
	 * @return  array 
	 **/
	private function getUserRoles(){
		$userData	= $this->getUserData();
		$roles		= $userData[self::ROLES];
		return $roles;
	}
	
	/**
	 * hasUserRole() used to check either the role is exists or not for peforming
	 * authorization process.
	 *
	 * @access	private
	 * @param	role
	 * @return  array 
	 **/
	private function hasUserRole($role){
		$userRoles 	= $this->getUserRoles();
		if(is_array($userRoles)){
			foreach($userRoles as $key => $value){
				if($role == $value){
					return true;
				}
			}
		}else{
			$value   = $userRoles;
			if($role == $value){
				return true;
			}
		}
		return false;
	}
	
	/**
	 * invalidUserData() used to invalidate Authenication and Authorization
	 * from active session.
	 *
	 * @access	private
	 * @return  void 
	 **/
	private function invalidUserData(){
		$this->setUserData(NULL);
	}
	
	/**
	 * setFlashData() used store application serverity messages in sessaion
	 * to view validation message in application
	 *
	 * @access	private
	 * param	data
	 * param	key
	 * @return  void 
	 **/
	private function setFlashData(Array $data = array(), $key = 'message'){
		$this->session->set_flashdata($key, $data);	
	}
	
	/**
	 * startSession() used to start session after successfully completing
	 * Authentication process.
	 *
	 * @access	private
	 * @return  void 
	 **/
	private function startSession(){
		$rules		= array('admin','sys');
		$userdata 	= array(
			'username' 		=> $this->username,
			self::ROLES 	=> $rules,
		);
		$this->setUserData($userdata);
	}
	
	/**
	 * stopSession() used to destroy session after successfully completing
	 * logout process.
	 *
	 * @access	private
	 * @return  void 
	 **/
	private function stopSession(){
		$this->invalidUserData();
	}
	
	/**
	 * redirect() used to redirect an action or in case of ajax request render
	 * json response.
	 *
	 * @access	private
	 * @param	action
	 * @param	success
	 * @return  void 
	 **/
	private function redirect($action, $success = false){
		$actionPath = base_url($action);
		if(!isAjaxRequest()){
			redirect($actionPath);
		}else{
			$message	= array(
				'redirect' => $actionPath,
				'message'  => $this->message
			);
			jsonRender($message, $success);
		}
	}
	
	/**
	 * validate() used to validate username and password from Authentication 
	 * form submitted data.
	 *
	 * @access	private
	 * @return  bool
	 **/
	private function validate(){
		$this->formValid->set_rules('username', 'Username', 'required|strip_tags');
        $this->formValid->set_rules('password', 'Password', 'required|strip_tags');
        if ($this->formValid->run() === FALSE){
            $message 		= validation_errors('<p>', '</p>');
			$this->message 	= $message;
            $this->setFlashData(array('class' => 'error', 'msg' => $message));
            $this->redirect($this->loginPage);
        }
		return true;
	}
	
	/**
	 * hasAuthority() used to check either user has the authorization or
	 * set severity message, in case of ajax request its render json
	 * response with message.
	 *
	 * @access	private
	 * @param	role
	 * @return  bool
	 **/
	private function hasAuthority($role){
		$hasAuthority = $this->hasUserRole($role);
		if(!$hasAuthority){
			$message		= $this->authorizationFailureMessage;
			$this->message 	= $message;
			if(!isAjaxRequest()){
				$this->setFlashData(array('class' => 'warn', 'msg' => $message));
				htmlRender($message, false);
			}else{
				jsonRender($message, false);
			}
		}
		return $hasAuthority;
	}
	
	/**
	 * sessionExpired() use in case of session expiration. This method perform
	 * to set severity message of session expiration, in case of ajax request
	 * its render json response with severity message.
	 *
	 * @access	private
	 * @return  void
	 **/
	private function sessionExpired(){
		$message 		= $this->sessionTimeOutMessage;
		$this->message 	= $message;
		$this->setFlashData(array('class' => 'success', 'msg' => $message));
		$this->redirect($this->logoutPage);
    }
	
	/**
	 * authenticate() used to authentication proccess to authenticate user to perform
	 * login. to set severity message for authentication, in case of ajax request its
	 * render json response with severity message.
	 *
	 * @access	public
	 * @return  void
	 **/
	public function authenticate(){
		$this->loadUserNameAndPassword();
		if($this->validate()){
            if($this->username == 'shahed' && $this->password = 'shahed'){
				$this->startSession();
				$message 		= $this->loginSuccessMessage;
				$this->message 	= $message;
                $this->setFlashData(array('class' => 'success', 'msg' => $message));
				$this->redirect($this->loginSuccessPage, true);				
			}else{
				$message 		= $this->loginFailureMessage;
				$this->message 	= $message;
				$this->setFlashData(array('class' => 'error', 'msg' => $message));
                $this->redirect($this->loginPage);
			}
        }
    }
	
	//UnitTestMock
	public function preAuthenticated(){
		$this->startSession();
	}
	
	/**
	 * isAuthenticated() used to check  a request whether it's authenticated or not.
	 * Its set severity message for authentication, in case of ajax request its
	 * render json response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticated(){
		$userData = $this->getUserData();
		$isAuthenticated = isset($userData) && !empty($userData);
		if(!$isAuthenticated){
			$this->sessionExpired();
		}
		return $isAuthenticated;
	}
	
	/**
	 * isAuthenticatedGetRequest() used to check  a request whether it's authenticated
	 * Get request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedGetRequest(){
		return $this->isAuthenticated && isGetRequest();
	}
	
	/**
	 * isAuthenticatedPostRequest() used to check  a request whether it's authenticated
	 * Post request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedPostRequest(){
		return $this->isAuthenticated && isPostRequest();	
	}
	
	/**
	 * isAuthenticatedPutRequest() used to check  a request whether it's authenticated
	 * Put request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedPutRequest(){
		return $this->isAuthenticated && isPutRequest();	
	}
	
	/**
	 * isAuthenticatedDeleteRequest() used to check  a request whether it's authenticated
	 * Delete request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedDeleteRequest(){
		return $this->isAuthenticated && isDeleteRequest();	
	}

	/**
	 * isAuthenticatedAjaxGetRequest() used to check  a request whether it's authenticated
	 * Ajax Get request or not.Its set severity message for authentication and render json
	 * response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedAjaxGetRequest(){
		return $this->isAuthenticated && isAjaxGetRequest();	
	}
	
	/**
	 * isAuthenticatedAjaxPostRequest() used to check  a request whether it's authenticated
	 * Ajax Post request or not.Its set severity message for authentication and render json
	 * response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedAjaxPostRequest(){
		return $this->isAuthenticated && isAjaxPostRequest();	
	}
	
	/**
	 * isAuthenticatedAjaxPutRequest() used to check  a request whether it's authenticated
	 * Ajax Put request or not.Its set severity message for authentication and render json
	 * response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedAjaxPutRequest(){
		return $this->isAuthenticated && isAjaxPutRequest();	
	}
	
	/**
	 * isAuthenticatedAjaxDeleteRequest() used to check  a request whether it's authenticated
	 * Ajax Delete request or not.Its set severity message for authentication and render json
	 * response with severity message.
	 *
	 * @access	public
	 * @return  bool
	 **/
	public function isAuthenticatedAjaxDeleteRequest(){
		return $this->isAuthenticated && isAjaxDeleteRequest();	
	}
	
	/**
	 * isAuthorized() used to check  a request whether it's Authorized or not.Its set 
	 * severity message for authentication, in case of ajax request its render json 
	 * response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorized($role){
		$isAuthorized	= $this->isAuthenticated();
		if($isAuthorized){
			$isAuthorized	= $this->hasAuthority($role);
		}
		return $isAuthorized;
	}
	
	/**
	 * isAuthorizedGetRequest() used to check  a request whether it's Authorized Get
	 * request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedGetRequest($role){
		return $this->isAuthorized($role) && isGetRequest();
	}
	
	/**
	 * isAuthorizedPostRequest() used to check  a request whether it's Authorized Post
	 * request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedPostRequest($role){
		return $this->isAuthorized($role) && isPostRequest();
	}
	
	/**
	 * isAuthorizedPutRequest() used to check  a request whether it's Authorized Put
	 * request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedPutRequest($role){
		return $this->isAuthorized($role) && isPutRequest();
	}
	
	/**
	 * isAuthorizedDeleteRequest() used to check  a request whether it's Authorized Delete
	 * request or not.Its set severity message for authentication, in case of ajax 
	 * request its render json response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedDeleteRequest($role){
		return $this->isAuthorized($role) && isDeleteRequest();
	}
	
	/**
	 * isAuthorizedAjaxGetRequest() used to check  a request whether it's Authorized Ajax
	 * Get request or not.Its set severity message for authentication and render json 
	 * response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedAjaxGetRequest($role){
		return $this->isAuthorized($role) && isAjaxGetRequest();
	}
	
	/**
	 * isAuthorizedAjaxPostRequest() used to check  a request whether it's Authorized Ajax
	 * Post request or not.Its set severity message for authentication and render json 
	 * response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedAjaxPostRequest($role){
		return $this->isAuthorized($role) && isAjaxPostRequest();
	}
	
	/**
	 * isAuthorizedAjaxPutRequest() used to check  a request whether it's Authorized Ajax
	 * Put request or not.Its set severity message for authentication and render json 
	 * response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedAjaxPutRequest($role){
		return $this->isAuthorized($role) && isAjaxPutRequest();
	}
	
	/**
	 * isAuthorizedAjaxDeleteRequest() used to check  a request whether it's Authorized Ajax
	 * Put request or not.Its set severity message for authentication and render json 
	 * response with severity message.
	 *
	 * @access	public
	 * @param	role
	 * @return  bool
	 **/
	public function isAuthorizedAjaxDeleteRequest($role){
		return $this->isAuthorized($role) && isAjaxDeleteRequest();
	}
	
	//UnitTestMock
	public function output(){		
		$jsonData = array('class' => 'success', 'msg' => 'helllo');		
		jsonRender($jsonData, false);
	}
	
	/**
	 * logout() used to sign out/logout after destroy session successfully.
	 * Use to completing logout process.
	 *
	 * @access	public
	 * @return  void 
	 **/
    public function logout(){
		$this->stopSession();
		$message = $this->logoutSuccessMessage;
		$this->setFlashData(array('class' => 'success', 'msg' => $message));
		$this->redirect($this->logoutPage, true);
    }
	
	/**
	 * encrypt() used to crypt/Crytography for digesting password and ensuring
	 * security of this application
	 *
	 * @access	public
	 * @return  string 
	 **/
    public function encrypt($password){
        if ($this->encrypt === TRUE && $password){
            $password = $this->salt ? $this->salt.$password : $password;
            $password = do_hash($password);
        }
		return $password;
    }
	
}

/* End of file Authentication.php */
/* Location: ./application/libraries/Authentication.php */